package com.lsh.ofc.worker.task;

import com.dangdang.ddframe.job.api.JobExecutionMultipleShardingContext;
import com.dangdang.ddframe.job.plugin.job.type.simple.AbstractSimpleElasticJob;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.base.common.json.JsonUtils2;
import com.lsh.ofc.core.entity.OfcOrderHead;
import com.lsh.ofc.core.entity.OfcSoHead;
import com.lsh.ofc.core.entity.OfcTask;
import com.lsh.ofc.core.enums.DistributionWay;
import com.lsh.ofc.core.enums.OfcTaskStatus;
import com.lsh.ofc.core.enums.OfcTaskType;
import com.lsh.ofc.core.enums.Region;
import com.lsh.ofc.core.model.StoSoHead;
import com.lsh.ofc.core.redis.RedisTemplate;
import com.lsh.ofc.core.service.OfcOrderService;
import com.lsh.ofc.core.service.OfcSoService;
import com.lsh.ofc.core.service.OfcTaskService;
import com.lsh.ofc.core.util.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Project Name: lsh-ofc
 * Created by fuhao
 * Date: 18/7/4
 * Time: 18/7/4.
 * 北京链商电子商务有限公司
 * Package name:com.lsh.ofc.worker.task.
 * desc:23点补单的定时任务
 *
 * @author fuhao
 */
@Slf4j
@Component
public class OfcStoFillTaskCreateJob extends AbstractSimpleElasticJob {
    @Autowired
    private OfcOrderService ofcOrderService;

    @Autowired
    private OfcTaskService ofcTaskService;

    @Autowired
    private OfcSoService ofcSoService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void process(JobExecutionMultipleShardingContext context) {
        // 默认100
        Integer fetchSize;

        try {
            log.info("ofc_task23 sto task create 开始...");
            long start = System.currentTimeMillis();
            String exeArgs = context.getJobParameter();
            exeArgs = StringUtils.isBlank(exeArgs) ? exeArgs : "22:30;22:30;20";
            String[] exeTimeArr = exeArgs.split(";");
            String startTimePoint = exeTimeArr[0];
            String endTimePoint = exeTimeArr[1];
            fetchSize = Integer.parseInt(exeTimeArr[2]);
            String[] startTimePointArr = startTimePoint.split(":");
            String[] endTimePointArr = endTimePoint.split(":");
            Date nowDate = new Date();
            Integer startTime = this.getStartTime(nowDate, Integer.parseInt(startTimePointArr[0]), Integer.parseInt(startTimePointArr[1]));
            Integer endTime = this.getEndTime(nowDate, Integer.parseInt(endTimePointArr[0]), Integer.parseInt(endTimePointArr[1]));

            List<OfcOrderHead> orders = ofcOrderService.findListFilterByTime(startTime, endTime, Region.BEIJING_CG.getCode(), DistributionWay.SEED_2_SHOP.getValue());
            // TODO: 18/6/19  如果客服未及时编辑，则在ofc没有这个单子，汇总会丢单子。
            log.info("[sto 汇总时间] 统计范围 {} - {} ,size = {}", new Object[]{startTime, endTime, orders.size()});

            // 按照200单为一个汇总sto任务
            int defaultSize = fetchSize;

            Map<String, List<StoSoHead>> stoMap = new HashMap<>(10);

            List<Long> orderCodeList = new ArrayList<>();
            for (OfcOrderHead order : orders) {
                //去重已经汇总的sto
                String orderStoKey = "sto:order:" + order.getOrderCode();
                if (redisTemplate.exists(orderStoKey)) {
                    continue;
                }
                orderCodeList.add(order.getOrderCode());
                OfcSoHead soFilter = new OfcSoHead();
                soFilter.setOrderCode(order.getOrderCode());
                List<OfcSoHead> sos = this.ofcSoService.findList(soFilter, false);
                // TODO: 18/6/19  默认订单都及时履约了
                if (CollectionUtils.isEmpty(sos)) {
                    log.error("SO信息不存在！订单号=" + order.getOrderCode());
                    // TODO: 18/6/19  此处要加redis，增加已处理的。
                }
                for (OfcSoHead ofcSoHead : sos) {
                    /* 按照前置仓ID+DC+货主拆sto任务  */
                    String stoKey = ofcSoHead.getPreWarehouseCode() + ofcSoHead.getSupplierDc() + ofcSoHead.getSupplierOrg();
                    List<StoSoHead> stoList = stoMap.get(stoKey);
                    if (null == stoList) {
                        stoList = new ArrayList<>();
                    }

                    StoSoHead stoSoHead = builderStoSoHead(ofcSoHead);

                    stoList.add(stoSoHead);
                    stoMap.put(stoKey, stoList);

                    if (stoList.size() == defaultSize) {
                        OfcTask ofcTask = new OfcTask();
                        // sto_code
                        ofcTask.setRefId(IdGenerator.genId());
                        ofcTask.setContent(JsonUtils2.obj2Json(stoList));
                        ofcTask.setStatus(OfcTaskStatus.NEW.getValue());
                        ofcTask.setType(OfcTaskType.STO_CREATE.getValue());
                        ofcTaskService.addTask(ofcTask);
                        stoMap.remove(stoKey);
                        for (Long orderCode : orderCodeList) {
                            redisTemplate.set("sto:order:" + orderCode.toString(), orderCode.toString(), 86400);
                        }
                        orderCodeList = new ArrayList<>();
                    }

                }
            }


            for (List<StoSoHead> entry : stoMap.values()) {
                OfcTask ofcTask = new OfcTask();
                ofcTask.setRefId(IdGenerator.genId());
                ofcTask.setContent(JsonUtils2.obj2Json(entry));
                ofcTask.setStatus(OfcTaskStatus.NEW.getValue());
                ofcTask.setType(OfcTaskType.STO_CREATE.getValue());
                ofcTaskService.addTask(ofcTask);
                for (Long orderCode : orderCodeList) {
                    redisTemplate.set("sto:order:" + orderCode.toString(), orderCode.toString(), 86400);
                }
            }

            long end = System.currentTimeMillis();
            log.info("ofc_task sto task create 完成... 处理行数：" + orders.size() + "，耗时：" + (end - start));
        } catch (BusinessException e) {
            log.error("ofc_task sto task create 异常... " + e.getMessage(), e);
        }
    }

    private StoSoHead builderStoSoHead(OfcSoHead ofcSoHead) {
        StoSoHead stoSoHead = StoSoHead.builder()
                .fulfillChannel(ofcSoHead.getFulfillChannel())
                .fulfillWms(ofcSoHead.getFulfillWms())
                .preWarehouseCode(ofcSoHead.getPreWarehouseCode())
                .regionCode(ofcSoHead.getRegionCode())
                .secondDistributionFlag(ofcSoHead.getSecondDistributionFlag())
                .soBillCode(ofcSoHead.getSoBillCode())
                .supplierDc(ofcSoHead.getSupplierDc())
                .supplierId(ofcSoHead.getSupplierId())
                .supplierOrg(ofcSoHead.getSupplierOrg())
                .totalSkuOrderQty(ofcSoHead.getTotalSkuOrderQty())
                .warehouseCode(ofcSoHead.getWarehouseCode())
                .warehouseName(ofcSoHead.getWarehouseName())
                .totalSkuSupplyQty(ofcSoHead.getTotalSkuSupplyQty())
                .build();
        return stoSoHead;
    }


    /**
     * 统计开始时间
     *
     * @param hourPoint 时间点
     * @return 时间戳
     */
    private Integer getStartTime(Date date, int hourPoint, int minutePoint) {

        return (int) TimeUnit.MILLISECONDS.toSeconds(this.getPreviousDayAndHourMorning(date, hourPoint, minutePoint).getTime());
    }

    /**
     * 统计结束时间
     *
     * @param hourPoint 时间点
     * @return 时间戳
     */
    private Integer getEndTime(Date date, int hourPoint, int minutePoint) {

        return (int) TimeUnit.MILLISECONDS.toSeconds(this.getDayHourMorning(date, hourPoint, minutePoint).getTime());
    }

    public Date getPreviousDayAndHourMorning(Date date, int hourPoint, int minutePoint) {


        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, hourPoint);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, minutePoint);
        cal.set(Calendar.MILLISECOND, 0);
        cal.add(Calendar.DATE, -1);

        return cal.getTime();
    }

    public Date getDayHourMorning(Date date, int hourPoint, int minutePoint) {

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, hourPoint);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, minutePoint);
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }
}
